using System;
using System.Collections;
using System.Collections.Specialized;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Evaluant.Uss;
using Evaluant.Uss.Commands;
using System.IO;
using System.Diagnostics;
using System.Threading;
using Evaluant.OPath;

namespace TestUSS
{
    /// <summary>
    /// Description résumée de Common.
    /// </summary>
    [TestClass]
    public class Common
    {
        protected IPersistenceEngine pe;
        protected IPersistenceProvider pef;

        public Common()
        {
            CreatePersistenceEngine();
            pef.RegisterMetaData(MetaDataFactory.FromMetaDataFile(@"..\..\..\NUnit\PersistenceEngine\Models\Common.xml"));
            pef.InitializeConfiguration();
            pe = pef.CreatePersistenceEngine();
        }

        [TestInitialize]
        public virtual void SetUp()
        {
            pe.InitializeRepository();
        }

        protected virtual void CreatePersistenceEngine()
        {
            pef = XmlConfigLoader.LoadXmlConfig("engines.config", "SqlServerSpecific"); // SqliteSpecific // SqlServerSpecific	// SqlGenAccess // SqlServerSpecificCCTable  //SqlServerSpecificSTable  //SqlServerSpecificMTable // CachedXml
        }

        [TestMethod]
        public virtual void ComplexTypes()
        {
            //pe.InitializeRepository();

            Entity e = new Entity("ComplexTypes");

            e.AddValue("datetime", new DateTime(2004, 1, 26, 13, 05, 46));
            //e.AddValue("timespan", new TimeSpan(26, 13, 05, 46));                     // TimeSpan not managed yet

            // Test arrays
            e.AddValue("array1", new string[] { "a", "b", "c" });
            e.AddValue("array2", new int[] { 1, 2, 3 });

            Transaction t = new Transaction();
            t.Serialize(e);
            t.Commit(pe);

            pe.Initialize();

            e = pe.Load("ComplexTypes")[0];

            Assert.AreEqual(new DateTime(2004, 1, 26, 13, 05, 46), e["datetime"]);
            //Assert.AreEqual (new TimeSpan (26, 13, 05, 46), e ["timespan"]);          // TimeSpan not managed yet

            pe.Initialize();

            // Check we can get back the values with an OPath query using the current culture encoding as OPath decodes DateTimes using current culture
            EntitySet es = pe.Load(String.Format("ComplexTypes[datetime = #{0}#]",
                new DateTime(2004, 1, 26, 13, 05, 46).ToString("s")));

            Assert.AreEqual(1, es.Count);
            Assert.AreEqual(new DateTime(2004, 1, 26, 13, 05, 46), es[0]["datetime"]);
            //Assert.AreEqual(new TimeSpan(26, 13, 05,46), es[0]["timespan"]);          // TimeSpan not managed yet

            // Date Time ordering
            es = pe.Load(String.Format("ComplexTypes[datetime > #{0}#]",
                new DateTime(2003, 1, 26, 13, 05, 46).ToString()));

            Assert.AreEqual(1, es.Count);

            es = pe.Load(String.Format("ComplexTypes[datetime > #{0}#]",
                new DateTime(2005, 1, 26, 13, 05, 46).ToString()));

            Assert.AreEqual(0, es.Count);

            string[] array1 = e["array1"] as string[];
            int[] array2 = e["array2"] as int[];

            Assert.IsNotNull(array1);
            Assert.AreEqual(3, array1.Length);
            Assert.AreEqual("a", array1[0]);

            Assert.IsNotNull(array2);
            Assert.AreEqual(3, array2.Length);
            Assert.AreEqual(1, array2[0]);

            // Enumerations must serialize as binary objects

            Entity p1 = new Entity("Category");
            p1.AddValue("Category", Category.Bug.ToString());

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.AreEqual(Category.Bug.ToString(), pe.Load("Category")[0]["Category"]);
            Assert.AreEqual(1, pe.Load("Category[Category = 'Bug']").Count);
        }

        [TestMethod]
        public virtual void UnicodeCharacters()
        {
            //            pe.InitializeRepository();
            //
            //            Entity str = new Entity("StringType");
            //            str.AddValue("Str", "short text");
            //            str.AddValue("UnicodeStr", ""客~""" ");
            //            str.AddValue("StrText", "very long text ...");
            //            str.AddValue("UnicodeStrText", "小:家謁大:~");
            //
            //            Transaction t = new Transaction();
            //            t.Serialize(str);
            //            t.Commit(pe);
            //
            //            Entity strLoaded = pe.Load("StringType")[0];
            //            Assert.AreEqual("short text", strLoaded.GetString("Str"));
            //            Assert.AreEqual(""客~""" ", strLoaded.GetString("UnicodeStr"));
            //            Assert.AreEqual("very long text ...", strLoaded.GetString("StrText"));
            //            Assert.AreEqual("小:家謁大:~", strLoaded.GetString("UnicodeStrText"));
        }

        public enum Category { Feature, Bug, Request }
        public enum ValueType { Int, String }

        [Flags]
        public enum FlaggedCategory { Feature = 1, Bug = 2, Request = 4, All = Feature | Bug | Request }

        [TestMethod]
        public virtual void TestKindDotName()
        {
            Entity k1 = new Entity("Kind");
            k1.AddValue("Name", "nice");
            k1.AddValue("Value", 1);

            Entity k2 = new Entity("Kind");
            k2.AddValue("Name", "bad");
            k2.AddValue("Value", 2);

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "John");
            p1.Id = "p1";

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Smith");
            p2.Id = "p2";

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "nice");
            p3.AddValue("Lastname", "Test");
            p3.Id = "p3";

            p1.AddValue("MyKind", k1);
            p1.AddValue("Brother", p2);

            p2.AddValue("MyKind", k2);

            p3.AddValue("MyKind", k1);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p3);
            t.Commit(pe);

            EntitySet es = pe.Load("Person");
            Assert.AreEqual(3, es.Count);

            es = pe.Load("Person[Firstname = 'Smith']");
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("Smith", es[0]["Firstname"]);

            es = pe.Load("Person[MyKind.Name = 'nice']");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("Person[MyKind.Name = 'bad']");
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("Smith", es[0]["Firstname"]);

            es = pe.Load("Person[Brother.MyKind.Name = 'bad']", new string[] { "Firstname" });
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("John", es[0]["Firstname"]);

            es = pe.Load("Person[Brother[Firstname = 'Smith'].MyKind.Name = 'bad']", new string[] { "Firstname" });
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("John", es[0]["Firstname"]);

            es = pe.Load("Person[Brother[Firstname = 'Toto'].MyKind.Name = 'bad']", new string[] { "Firstname" });
            Assert.AreEqual(0, es.Count);

            es = pe.Load("Person[MyKind.Name = Firstname]");
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("Test", es[0]["Lastname"]);
        }


        [TestMethod]
        public virtual void ShouldHandleKeywordsInStrings()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "max");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load("Person").Count);
            Assert.AreEqual(1, pe.Load("Person[Firstname='max']").Count);

        }

        [TestMethod]
        public virtual void OrderedSubQuery()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.AreEqual(2, pe.Load("Person[Firstname = 'p1'].Partners", "Firstname", 1, 0).Count);
        }

        [TestMethod]
        public virtual void Ids()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Fabien");
            p1.Id = "p1";

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Laurent");
            p2.Id = "p2";

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Séb");
            p3.Id = "p3";

            Entity a1 = new Entity("Address");
            a1.AddValue("City", "Mulhouse");
            a1.Id = "a1";

            Entity a2 = new Entity("Address");
            a2.AddValue("City", "Hegenheim");
            a2.Id = "a2";

            p1.AddValue("Address", a2);
            p1.AddValue("Partners", p2);
            p2.AddValue("Address", a1);
            p3.AddValue("Address", a1);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pe);

            EntitySet es = pe.Load("Person");
            Assert.AreEqual(3, es.Count);

            pe.LoadReference(es, new string[] { "Address" });

            foreach (Entity e in es)
                Assert.AreEqual(1, e.GetEntitySet("Address").Count);

            p1 = pe.Load("Person[exists(Address[id('a2')]) and exists(Partners[Firstname = 'Laurent']) and Firstname = 'Fabien' ]")[0];

            Assert.IsNotNull(p1);
            Assert.AreEqual("Fabien", p1["Firstname"]);

            pe.LoadReference(p1, new string[] { "Address", "Partners" });

            Assert.AreEqual("Hegenheim", p1.GetEntity("Address")["City"]);
            Assert.AreEqual("Laurent", p1.GetEntitySet("Partners")[0]["Firstname"]);

            Assert.AreEqual(2, pe.Load("Person[ not id('p1') ]").Count);
        }

        [TestMethod]
        public virtual void Simple()
        {
            pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Thomas");
            p1.AddValue("Lastname", "Gil");
            p1.AddValue("Age", 27);

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Sébastien");
            p2.AddValue("Lastname", "Ros");
            p2.AddValue("Age", 27);

            p1.AddValue("Partners", p2);
            p2.AddValue("Partners", p1); // To test cyclic references

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            EntitySet es = pe.Load("Person");

            p1.DeleteElement("Firstname");

            t = new Transaction();
            t.Serialize(p1);

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Nicolas");
            p3.AddValue("Lastname", "Chabrier");
            p3.AddValue("Age", 27);
            p3.AddValue("Prout", p2);

            t.Serialize(p3);
            t.Commit(pe);

            t = new Transaction();
            t.Delete(p1);
            t.Serialize(p3);
            t.Commit(pe);
        }

        /// <summary>
        /// Checks the whether the technique used in the PM for bidirectional relationships works 
        /// </summary>
        [TestMethod]
        public virtual void BackRef()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            p1.AddValue("Partners", p2);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            EntitySet es = pe.Load(String.Concat("Person[ count(Partners[id('", p2.Id, "')]) > 0]"));

            Assert.AreEqual(1, es.Count);


            Assert.AreEqual("p1", pe.Load(String.Concat("Person[ count(Partners[id('", p2.Id, "')]) > 0]"))[0]["Firstname"]);
        }

        //[TestMethod]
        //public virtual void EnumerationFlag()
        //{
        //    Entity p2 = new Entity("FlaggedCategory");
        //    p2.AddValue("FlaggedCategory", FlaggedCategory.Feature | FlaggedCategory.Request);

        //    Transaction t = new Transaction();
        //    t.Serialize(p2);
        //    t.Commit(pe);

        //    Entity p = pe.Load("FlaggedCategory")[0];
        //    Assert.AreEqual(FlaggedCategory.Feature | FlaggedCategory.Request, p["FlaggedCategory"]);
        //}

        [TestMethod]
        public virtual void Create()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);
        }

        [TestMethod]
        public virtual void Update()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();
            p1["Firstname"] = "new_name";

            Entity p4 = new Entity("Person");
            p4["Firstname"] = "p4";
            p1.AddValue("Brother", p4);

            p1.AddValue("Age", 12);

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();
            EntitySet e = pe.Load("Person[Firstname = 'new_name']");
            Assert.AreEqual(1, e.Count);

            pe.LoadReference(new Entity[] { e[0] }, new string[] { "Brother" });
            Assert.IsNotNull(e[0].GetEntity("Brother"));
        }

        [TestMethod]
        public virtual void CompoundCommands()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");
            p1.AddValue("Age", 18);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            p1.AddValue("Acceleration", 9.81); // CreateAttributeCommand
            p1.SetValue("Age", 19); // UpdateAttributeCommand

            // Should still create only one CompoundUpdateCommand

            Hashtable processng = new Hashtable();

            Assert.AreEqual(1, Entity.ComputeChanges(p1).Count);
        }

        [TestMethod]
        public virtual void UpdateReference()
        {
            //pe.InitializeRepository();

            Entity x = new Entity("X");
            x.AddValue("xvalue", "val x");

            Entity y = new Entity("Y");
            y.AddValue("yvalue", "val y");

            x.AddValue("YRef", y);

            Transaction t = new Transaction();
            t.Serialize(x);
            t.Commit(pe);

            Entity e = pe.Load("X")[0];
            Assert.IsNotNull(e);

            pe.LoadReference(e, new string[] { "YRef" });
            Assert.AreEqual(1, e.GetEntitySet("YRef").Count);

            e.GetEntitySet("YRef")[0] = y;

            t = new Transaction();
            t.Serialize(e);
            t.Commit(pe);

            e = pe.Load("X")[0];
            Assert.IsNotNull(e);

            pe.LoadReference(e, new string[] { "YRef" });
            Assert.AreEqual(1, e.GetEntitySet("YRef").Count);

            EntitySet es = pe.Load("Y");
            Assert.AreEqual(1, es.Count);
        }


        [TestMethod]
        public virtual void LoadReference()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();
            Entity p = pe.Load("Person[Firstname = 'p1']")[0];
            Assert.AreEqual(State.UpToDate, p.State);

            pe.LoadReference(new Entity[] { p }, new string[] { "Partners" });

            Assert.AreEqual(State.UpToDate, p.State);

            foreach (Entity e in p.GetEntitySet("Partners"))
                Assert.AreEqual(State.UpToDate, e.State);

            Assert.AreEqual(2, p.GetEntitySet("Partners").Count);

            Entity s1 = new Entity("Company");
            s1.AddValue("Name", "evaluant");

            Entity s2 = new Entity("Company");
            s2.AddValue("Name", "microsoft");

            p1.AddValue("MyCompany", s1);

            p2.AddValue("MyCompany", s1);
            p2.AddValue("MyCompany", s2);

            p3.AddValue("MyCompany", s1);

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();
            p = pe.Load("Person[Firstname = 'p1']")[0];
            pe.LoadReference(p, new string[] { "MyCompany" });

            Assert.AreEqual(State.UpToDate, p.State);
            foreach (EntityEntry e in p)
            {
                Assert.AreEqual(State.UpToDate, e.State);
            }
            foreach (Entity e in p.GetEntitySet("MyCompany"))
            {
                Assert.AreEqual(State.UpToDate, e.State);
            }
            Assert.AreEqual(1, p.GetEntitySet("MyCompany").Count, "Reference 'MyCompany' not found");

            p = pe.Load("Person[Firstname = 'p2']")[0];
            pe.LoadReference(p, new string[] { "MyCompany" });

            Assert.AreEqual(State.UpToDate, p.State);
            foreach (EntityEntry e in p)
            {
                Assert.AreEqual(State.UpToDate, e.State);
            }
            foreach (Entity e in p.GetEntitySet("MyCompany"))
            {
                Assert.AreEqual(State.UpToDate, e.State);
            }
            Assert.AreEqual(2, p.GetEntitySet("MyCompany").Count, "Reference 'MyCompany' not found");

            p = pe.Load("Person[Firstname = 'p3']")[0];
            pe.LoadReference(p, new string[] { "MyCompany" });

            Assert.AreEqual(State.UpToDate, p.State);
            foreach (EntityEntry e in p)
            {
                Assert.AreEqual(State.UpToDate, e.State);
            }

            foreach (Entity e in p.GetEntitySet("MyCompany"))
            {
                Assert.AreEqual(State.UpToDate, e.State);
            }

            Assert.AreEqual(1, p.GetEntitySet("MyCompany").Count);
        }

        [TestMethod]
        public virtual void LoadReference2()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity s1 = new Entity("Company");
            s1.AddValue("Name", "evaluant");

            Entity s2 = new Entity("Company");
            s2.AddValue("Name", "toto");

            p1.AddValue("MyCompany", s1);
            p1.AddValue("MyCompany", s2);

            Transaction t = new Transaction();
            t.Serialize(s1);
            t.Serialize(s2);
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();
            Entity p = pe.Load("Person[count(MyCompany[id('" + s1.Id + "')]) > 0]")[0];

            Assert.IsNotNull(p);
            Assert.AreEqual("p1", p["Firstname"]);

            pe.LoadReference(p, new string[] { "MyCompany" });

            Assert.AreEqual(2, p.GetEntitySet("MyCompany").Count);

            StringCollection names = new StringCollection();
            names.Add("toto");
            names.Add("evaluant");

            foreach (Entity s in p.GetEntitySet("MyCompany"))
            {
                Assert.IsTrue(names.Contains(s.GetString("Name")));
                names.Remove(s.GetString("Name"));
            }
        }

        [TestMethod]
        public virtual void References3()
        {
            //pe.InitializeRepository();

            Entity s1 = new Entity("Test:Company");
            s1.AddValue("Name", "s");

            Entity c1 = new Entity("Test:Contract");
            c1.AddValue("Heading", "h");
            c1.AddValue("MyCompany", s1);

            Transaction t = new Transaction();
            t.Serialize(c1);
            t.Commit(pe);

            EntitySet es = pe.Load("Test:Contract.MyCompany");

            Assert.AreEqual(1, es.Count);

            c1 = (Entity)pe.Load("Test:Contract")[0];

            Assert.IsNotNull(c1);
            Assert.AreEqual("h", c1["Heading"]);

            pe.LoadReference(c1, new string[] { "MyCompany" });

            Assert.AreEqual(1, c1.GetEntitySet("MyCompany").Count);

            s1 = c1.GetEntitySet("MyCompany")[0];

            Assert.AreEqual("s", s1["Name"]);
        }

        [TestMethod]
        public virtual void DeleteEntity()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            t = new Transaction();
            t.Delete(p1);
            t.Commit(pe);

            pe.Initialize();

            Assert.AreEqual(0, pe.Load("Person").Count);
        }

        [TestMethod]
        public virtual void DeleteAttribute()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load("Person[Firstname = 'p1']").Count);

            p1["Firstname"] = null;

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();

            Assert.AreEqual(0, pe.Load("Person[Firstname = 'p1']").Count);
        }

        [TestMethod]
        public virtual void Delete()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();

            // Removes an attribute
            //			p2.RemoveAttribute("Firstname");
            p2["Firstname"] = null;
            p1.AddValue("Lastname", "TestValue");

            t = new Transaction();
            t.Delete(p3);
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();

            Assert.AreEqual(2, pe.Load("Person").Count);
            Assert.AreEqual("TestValue", pe.Load("Person[Firstname = 'p1']")[0]["Lastname"]);
            Assert.AreEqual(0, pe.Load("Person[Firstname = 'p2']").Count);

            p1.DeleteElement("Lastname");

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            pe.Initialize();

            // Check the attribute "Test" is deleted from p1
            Assert.IsNull(pe.Load("Person[Firstname = 'p1']")[0]["Lastname"]);
        }

        [TestMethod]
        public virtual void ValueTypes()
        {
            Entity e = new Entity("ValueTypes");
            e.AddValue("bool", true);
            e.AddValue("byte", (byte)0);
            e.AddValue("sbyte", (sbyte)0);
            e.AddValue("char", 'a');
            e.AddValue("decimal", (decimal)0.2);
            e.AddValue("double", 0.2);
            e.AddValue("float", (float)0.2);
            e.AddValue("int", 0);
            e.AddValue("uint", (uint)0);
            e.AddValue("long", (long)0);
            e.AddValue("ulong", (ulong)0);
            e.AddValue("short", (short)0);
            e.AddValue("ushort", (ushort)0);
            e.AddValue("string", "string");
            e.AddValue("object", new byte[] { (byte)1, (byte)2 });
            e.AddValue("object2", "toto");

            Transaction t = new Transaction();
            t.Serialize(e);
            t.Commit(pe);

            e = pe.Load("ValueTypes")[0];

            Assert.IsTrue(e["bool"].Equals(true), "Error 'bool'");
            Assert.IsTrue(e["byte"].Equals((byte)0), "Error 'byte'");
            Assert.IsTrue(e["sbyte"].Equals((sbyte)0), "Error 'sbyte'");
            Assert.IsTrue(e["char"].Equals('a'), "Error 'char'");
            Assert.IsTrue(e["double"].Equals(0.2), "Error 'double'");
            Assert.IsTrue(e["float"].Equals((float)0.2), "Error 'float'");
            Assert.IsTrue(e["int"].Equals(0), "Error 'int'");
            Assert.IsTrue(e["uint"].Equals((uint)0), "Error 'uint'");
            Assert.IsTrue(e["long"].Equals((long)0), "Error 'long'");
            Assert.IsTrue(e["ulong"].Equals((ulong)0), "Error 'ulong'");
            Assert.IsTrue(e["short"].Equals((short)0), "Error 'short'");
            Assert.IsTrue(e["ushort"].Equals((ushort)0), "Error 'ushort'");
            Assert.IsTrue(e["string"].Equals("string"), "Error 'string'");
            Assert.IsTrue(e["decimal"].Equals((decimal)0.2), "Error 'decimal'");
            byte[] array1 = e["object"] as byte[];
            Assert.AreEqual(array1[0], (byte)1, "Error 'object'");
            Assert.IsTrue(e["object2"].Equals("toto"), "Error 'object2'");
        }

        [TestMethod]
        public virtual void Culture()
        {
            Assert.IsNotNull(pe.Culture);
        }

        [TestMethod]
        public virtual void DateTimeType()
        {
            Entity e1 = new Entity("ComplexTypes");

            Transaction t = new Transaction();
            t.Serialize(e1);
            t.Commit(pe);

            Assert.AreEqual(0, pe.LoadScalar(String.Format("count(ComplexTypes[datetime = #{0}#])", new DateTime(2006, 1, 13).ToShortDateString())));

            // only Date
            e1.AddValue("datetime", new DateTime(2006, 1, 13));

            t = new Transaction();
            t.Serialize(e1);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load(String.Format("ComplexTypes[datetime = #{0}#]", new DateTime(2006, 1, 13).ToShortDateString())).Count);
            Assert.AreEqual(0, pe.Load(String.Format("ComplexTypes[datetime = #{0}#]", new DateTime(2006, 1, 13, 14, 0, 0).ToString())).Count);

            // Date & time
            e1["datetime"] = new DateTime(2006, 1, 13, 14, 0, 0, 0);

            t = new Transaction();
            t.Serialize(e1);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load(String.Format("ComplexTypes[datetime = #{0}#]", new DateTime(2006, 1, 13, 14, 0, 0).ToString())).Count);
        }

        [TestMethod]
        public virtual void SerializableTypes()
        {
            Entity e = new Entity("SerializableTypes");

            StringCollection strings = new StringCollection();
            strings.Add("a");
            strings.Add("b");
            strings.Add("c");

            e.AddValue("StringCollection", strings);

            Transaction t = new Transaction();
            t.Serialize(e);
            t.Commit(pe);

            e = pe.Load("SerializableTypes")[0];

            strings = e["StringCollection"] as StringCollection;

            Assert.IsNotNull(strings);
            Assert.AreEqual(3, strings.Count, "Error 'StringCollection'");
            Assert.AreEqual("a", strings[0]);
            Assert.AreEqual("b", strings[1]);
            Assert.AreEqual("c", strings[2]);
        }

        [TestMethod]
        public virtual void ComplexOPath()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Entity p4 = new Entity("Person");
            p4.AddValue("Firstname", "p4");
            p4.AddValue("Age", "27");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);
            p2.AddValue("Partners", p4);
            p4.AddValue("Partners", p1);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load("Person[(Firstname = 'p1' or Firstname = 'p1' ) and Firstname = 'p1' and (Firstname = 'p1' or (Firstname = 'p1' and ( not exists(Partners) or exists(Partners[Firstname = 'p1']))))]").Count);

            //pe.InitializeRepository();

            Entity s1 = new Entity("Student");
            s1.AddValue("Name", "John");

            Entity s2 = new Entity("Student");
            s2.AddValue("Name", "Kelly");

            Entity c2 = new Entity("Course");
            c2.AddValue("Subject", "Mathematics");
            c2.AddValue("NbHours", 2);

            Entity c3 = new Entity("Course");
            c3.AddValue("Subject", "French");
            c3.AddValue("NbHours", 3);

            Entity c4 = new Entity("Course");
            c4.AddValue("Subject", "History");
            c4.AddValue("NbHours", 4);

            Entity c5 = new Entity("Course");
            c5.AddValue("Subject", "Economy");
            c5.AddValue("NbHours", 5);

            s1.AddValue("MyCourse", c2);
            s1.AddValue("MyCourse", c3);
            s1.AddValue("MyCourse", c4);

            s2.AddValue("MyCourse", c3);
            s2.AddValue("MyCourse", c5);

            t = new Transaction();
            t.Serialize(s1);
            t.Serialize(s2);
            t.Commit(pe);

            //Assert.AreEqual(1, pe.Load("Student[Name='John'].MyCourse[NbHours = max(NbHours)]").Count);
            //Assert.AreEqual("History", pe.Load("Student[Name='John'].MyCourse[NbHours = max(NbHours)]")[0].GetString("Subject"));
            //Assert.AreEqual("History", pe.Load("Student[Name='John' and MyCourse.NbHours = max(MyCourse.NbHours)].MyCourse")[0].GetString("Subject"));
        }

        [Ignore]
        public virtual void OPathException()
        {
            try
            {
                pe.Load("Person[ Test and or Toto ]");
            }
            catch (Exception e)
            {
                Assert.AreEqual(typeof(OPathException), e.GetType());
                return;
            }

            Assert.Fail();
        }

        [TestMethod]
        public virtual void ManyToMany()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Thomas");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Sébastien");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Nicolas");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            EntitySet people = pe.Load("Person");

            Assert.AreEqual(people.Count, 3);
        }

        [TestMethod]
        public virtual void LazyLoadingManyToMany()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Thomas");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Sébastien");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Nicolas");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            EntitySet people = pe.Load("Person");
            pe.LoadReference(people, new string[] { "Partners" });
        }

        [TestMethod]
        public virtual void LazyLoadingOneToMany()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Thomas");

            Entity t1 = new Entity("Thing");
            t1.AddValue("Firstname", "t1");

            Entity t2 = new Entity("Thing");
            t2.AddValue("Firstname", "t2");

            Entity t3 = new Entity("Thing");
            t3.AddValue("Firstname", "t3");

            p1.AddValue("ToMany", t1);
            p1.AddValue("ToMany", t2);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(t3);
            t.Commit(pe);

            EntitySet people = pe.Load("Person");
            pe.LoadReference(people, new string[] { "ToMany" });

            Assert.AreEqual(2, people[0].GetEntitySet("ToMany").Count);
        }

        [TestMethod]
        public virtual void InferredRelationshipIntegrity()
        {

            // Loads two times the relationships to find out a possible integrity bug

            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);

            p1.AddValue("Subsidiaries", p3);
            p2.AddValue("Subsidiaries", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            p1 = pe.Load("Person[ Firstname = 'p1' ]")[0];
            p2 = pe.Load("Person[ Firstname = 'p2' ]")[0];
            p3 = pe.Load("Person[ Firstname = 'p3' ]")[0];

            Assert.IsTrue(p1 != null && p2 != null && p3 != null);

            pe.LoadReference(p1, new string[] { "Partners", "Subsidiaries" });
            pe.LoadReference(p2, new string[] { "Partners", "Subsidiaries" });
            pe.LoadReference(p3, new string[] { "Partners", "Subsidiaries" });

            pe.LoadReference(p1, new string[] { "Partners", "Subsidiaries" });
            pe.LoadReference(p2, new string[] { "Partners", "Subsidiaries" });
            pe.LoadReference(p3, new string[] { "Partners", "Subsidiaries" });

            Assert.AreEqual(2, p1.GetEntitySet("Partners").Count);
            Assert.AreEqual(1, p1.GetEntitySet("Subsidiaries").Count);

            Assert.AreEqual(0, p2.GetEntitySet("Partners").Count);
            Assert.AreEqual(1, p2.GetEntitySet("Subsidiaries").Count);

            Assert.AreEqual(0, p3.GetEntitySet("Partners").Count);
            Assert.AreEqual(0, p3.GetEntitySet("Subsidiaries").Count);
        }

        protected bool Contains(EntitySet coll, Entity entity)
        {
            foreach (Entity e in coll)
            {
                if (e.Id == entity.Id)
                    return true;
            }
            return false;
        }

        [TestMethod]
        [MTAThread]
        public virtual void NullArgument()
        {
            // Tests if a null or String.Empty value are correctly deserialized

            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");
            p2.AddValue("Lastname", String.Empty);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Commit(pe);

            p1 = pe.Load("Person[ Firstname='p1']")[0];
            Assert.AreEqual("p1", p1.GetValue("Firstname"));
            Assert.IsNull(p1.GetValue("Lastname"), "p1");

            p2 = pe.Load("Person[ Firstname='p2']")[0];
            Assert.AreEqual("p2", p2.GetValue("Firstname"));
            Assert.AreEqual(String.Empty, p2.GetValue("Lastname"), "p2");
        }

        [TestMethod]
        public virtual void OPathSpecialChars()
        {
            //pe.InitializeRepository();
            pe.Load("Person[Firstname = '°²']");
        }

        [TestMethod]
        public virtual void OPath()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");
            p1.AddValue("Acceleration", (decimal)9.81);

            Entity p2 = new Entity("Person");
            p2.AddValue("Age", 33);
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Age", 27);
            p3.AddValue("Firstname", "p3");

            Entity p4 = new Entity("Thing");
            p4.AddValue("Firstname", "a'b");
            p4.AddValue("Lastname", "a~b");

            p1.AddValue("Partners", p2);
            p1.AddValue("BestFriend", p2);
            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);
            p2.AddValue("BestFriend", p3);
            p2.AddValue("Friends", p4);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            // A constraint can't begin with a relation's name: must be attribute or commmand. Ex: Person[Partners] is not allowed
            // Person.Firstname can't be used in a constraint, but Person[Firstname]

            // TODO : if a constraint starts with a Path, include it in an exists() clause

            EntitySet coll = pe.Load("Person[ Firstname='p1']");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ 'p1' = Firstname]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ exists(Partners) ]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ exists(Partners) and exists(Friends) ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person.Partners");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p2));
            Assert.IsTrue(Contains(coll, p3));

            coll = pe.Load("Person[ Firstname='p2'].Partners");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p3));

            coll = pe.Load("Person.Partners.Partners");
            Assert.AreEqual(1, coll.Count);

            coll = pe.Load("Person[ Firstname='p1'].Partners.Partners");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p3));

            coll = pe.Load("Person[ Firstname='p1' ].Partners[ exists( Partners[ Firstname = 'p3'] ) ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ Firstname='p1'].Partners[ Firstname='p3']");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p3));

            coll = pe.Load("Person[ exists(Partners) ]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ Firstname = 'p1' or Firstname = 'p2' ]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ exists(Partners[isNull(Acceleration)]) ]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p2));
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ exists(Partners.Partners[Firstname = 'p3']) ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ exists(Partners.Partners[id('" + p3.Id + "')]) ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ exists(BestFriend[exists(BestFriend[Firstname = 'p3'])]) ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person.BestFriend.BestFriend");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p3));

            Assert.AreEqual(0, pe.Load("Person[ Firstname = 'p1' and Firstname = 'p2' ]").Count, "Error 'Person[ Firstname = 'p1' and Firstname = 'p2' ]'");

            coll = pe.Load("Person[ Firstname = 'p1' or exists(Partners[ Firstname = 'p3' ]) ]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));


            coll = pe.Load("Person[ not exists(Partners) ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p3));

            coll = pe.Load("Person[ Firstname ~ 'p' ]");
            Assert.AreEqual(3, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));
            Assert.IsTrue(Contains(coll, p3));

            Assert.AreEqual(0, pe.Load("Person[ Firstname ^ 'stuff' ]").Count, "Error 'Person[ Firstname ^ 'stuff' ]'");

            coll = pe.Load("Person[ Firstname ~ '1' ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            Assert.AreEqual(0, pe.Load("Person[ Firstname ~ 'stuff' ]").Count, "Error 'Person[ Firstname ~ 'stuff' ]'");

            Assert.AreEqual(0, pe.Load("Person[ Firstname ^ '/p' ]").Count, "Error 'Person[ Firstname ^ '/p' ]'");
            Assert.AreEqual(0, pe.Load("Person[ Firstname ^ '~stuff' ]").Count, "Error 'Person[ Firstname ^ '~stuff' ]'");
            Assert.AreEqual(0, pe.Load("Person[ Firstname ^ '~/stuff' ]").Count, "Error 'Person[ Firstname ^ '~/stuff' ]'");

            // escape characters
            coll = pe.Load("Thing[ Firstname = 'a\\'b' ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p4));

            coll = pe.Load(@"Thing[ Firstname = 'a\'b' ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p4));

            coll = pe.Load(@"Thing[ Firstname ~ 'a\'b' ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p4));

            coll = pe.Load(@"Thing[ Firstname = 'a\'b' and Lastname = 'a~b']");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p4));

            // id() management
            coll = pe.Load("Person[id('" + p1.Id + "')].Partners");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p2));
            Assert.IsTrue(Contains(coll, p3));

            coll = pe.Load("Person[id('" + p1.Id + "')].Partners.Partners");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p3));

            coll = pe.Load("Person[exists(Partners[id('" + p2.Id + "')])]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[id('" + p1.Id + "') or id('" + p2.Id + "')]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            //test id() function with 2 arguments
            coll = pe.Load(string.Format("Person[id('{0}', '{1}')]", p1.Id, p2.Id));
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            Assert.AreEqual(0, pe.Load("Person[id('" + p1.Id + "') and id('" + p2.Id + "')]").Count);

            coll = pe.Load("Person[id('" + p1.Id + "') or exists(Partners[id('" + p3.Id + "')])]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ 2 = count(Partners)]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ 2 = count(Partners)]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ 2 = count(Partners) or count(Partners) = 1]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ isNull(Age) ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            // floating point numbers parsing
            Assert.AreEqual(1, pe.Load("Person[Acceleration = 9.81]").Count);

            coll = pe.Load("Person[ max(Partners.Age)  = 27 ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ min(Partners.Age)  = 27 ]");
            Assert.AreEqual(2, coll.Count);
            Assert.IsTrue(Contains(coll, p1));
            Assert.IsTrue(Contains(coll, p2));

            coll = pe.Load("Person[ avg(Partners.Age)  = 30 ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

            coll = pe.Load("Person[ sum(Partners.Age)  = 60 ]");
            Assert.AreEqual(1, coll.Count);
            Assert.IsTrue(Contains(coll, p1));

        }

        [TestMethod]
        public virtual void Parents()
        {
            //			Entity p1 = new Entity("Person");
            //			p1.AddValue("Name", "p1");
            //
            //			Entity p2 = new Entity("Person");
            //			p2.AddValue("Name", "p2");
            //
            //			p1.AddValue("Partners", p2);
            //
            //			Transaction t = new Transaction();
            //			t.Serialize(p1);
            //			t.Commit(pe);

            EntitySet es = pe.Load("Person");

            foreach (Entity e in es)
            {
                Console.WriteLine(e.GetValue("Name"));
                if (e.GetValue("Name").Equals("p1"))
                {
                    pe.LoadReference(e, new string[] { "Partners" });
                    //Assert.AreEqual(1, e.GetEntitySet("Partners").Count);
                    Console.WriteLine(e.GetEntitySet("Partners").Count);
                }
            }
        }

        [TestMethod]
        public virtual void References()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);
        }

        [TestMethod]
        public virtual void References2()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Manager");

            Entity p2 = new Entity("Manager");

            Entity c = new Entity("Company");
            c.AddValue("Name", "comp");

            p1.AddValue("MyCompany", c);
            p2.AddValue("MyCompany", c);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Commit(pe);

            EntitySet es = pe.Load("Manager.MyCompany");
            Assert.AreEqual(1, es.Count);

            p1 = (Entity)pe.Load(string.Concat("Manager[ id( '", p1.Id, "' ) ]"))[0];
            Assert.IsNotNull(p1);
            pe.LoadReference(p1, new string[] { "MyCompany" });

            p2 = (Entity)pe.Load(string.Concat("Manager[ id( '", p2.Id, "' ) ]"))[0];
            Assert.IsNotNull(p2);
            pe.LoadReference(p2, new string[] { "MyCompany" });
        }

        [TestMethod]
        public virtual void LoadState()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p2);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load("Person.Partners").Count);

            p1.AddValue("Partners", p3);

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.AreEqual(2, pe.Load("Person.Partners").Count);

            p2.AddValue("Partners", p1);

            t = new Transaction();
            t.Serialize(p2);
            t.Commit(pe);

            Assert.AreEqual(3, pe.Load("Person.Partners").Count);

            // It is possible to add the same reference twice. It must create two relationships
            p2.AddValue("Partners", p3);

            t = new Transaction();
            t.Serialize(p2);
            t.Commit(pe);

            Assert.AreEqual(3, pe.Load("Person.Partners").Count);

        }

        [TestMethod]
        public virtual void BusinessId()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Firstname1");
            p1.Id = "1";

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Firstname2");
            p2.Id = "2";

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Firstname3");
            p3.Id = "3";

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Assert.IsNotNull(pe.LoadWithId("Person", new string[] { "1" }));
            Assert.IsNotNull(pe.LoadWithId("Person", new string[] { "2" }));
            Assert.IsNotNull(pe.LoadWithId("Person", new string[] { "3" }));

            Assert.AreEqual("Firstname1", pe.LoadWithId("Person", "1")["Firstname"]);
            Assert.AreEqual("Firstname2", pe.LoadWithId("Person", "2")["Firstname"]);
            Assert.AreEqual("Firstname3", pe.LoadWithId("Person", "3")["Firstname"]);

            Assert.AreEqual("Firstname1", pe.LoadWithId("Person", p1.Id)["Firstname"]);

        }

        [TestMethod]
        public virtual void Commands()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Firstname1");
            p1.Id = "1";

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Firstname2");
            p2.Id = "2";

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Firstname3");
            p3.Id = "3";

            Command command;

            Transaction t = new Transaction();
            command = new CreateReferenceCommand("Partners", p1.Id, "Person", p2.Id, "Person");
            t.PushCommand(new Command[] { command });
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load("Person.Partners").Count);

            t = new Transaction();
            command = new DeleteReferenceCommand("Partners", p1.Id, "Person", p2.Id, "Person");
            t.PushCommand(new Command[] { command });
            t.Commit(pe);

            Assert.AreEqual(0, pe.Load("Person.Partners").Count);

            // Checks that a modified entity only returns the modified commands

            p1.SetValue("Age", 12);

            ICollection commands = Entity.ComputeChanges(p1);

            Assert.AreEqual(1, commands.Count);
            foreach (Command c in commands)
                Assert.IsTrue(c is CreateAttributeCommand);

        }

        [TestMethod]
        public virtual void Inheritance()
        {
            pe.InitializeRepository();

            Entity bill = new Entity("Employee");
            bill.AddValue("Firstname", "Bill Gates");
            bill.AddValue("Salary", 99999F);

            Entity redmond = new Entity("Address");
            redmond.AddValue("City", "Redmond");
            bill.AddValue("Address", redmond);

            Entity paloalto = new Entity("Address");
            paloalto.AddValue("City", "Palo Alto");

            Entity steve = new Entity("Person");
            steve.AddValue("Firstname", "Steve Jobs");
            steve.AddValue("Address", paloalto);

            bill.AddValue("Partners", steve);

            Transaction t = new Transaction();
            t.Serialize(bill);
            t.Commit(pe);

            Assert.AreEqual(2, pe.Load("Person").Count);
            Assert.AreEqual(2, pe.Load("Address").Count);

            bill = pe.Load("Employee[Firstname = 'Bill Gates']")[0];
            Assert.IsNotNull(bill);
            Assert.AreEqual(99999F, bill["Salary"]);

            pe.LoadReference(bill, new string[] { "Partners", "Address" });

            Assert.AreEqual("Steve Jobs", bill.GetEntitySet("Partners")[0]["Firstname"]);
            Assert.AreEqual("Redmond", bill.GetEntity("Address")["City"]);
        }

        [TestMethod]
        public virtual void PagingShouldNotReturnTooManyItemsOnTheLastPage()
        {
            //pe.InitializeRepository();

            Transaction t = new Transaction();
            for (int i = 1; i <= 15; i++)
            {
                Entity e = new Entity("Person");
                e["Age"] = i;
                t.Serialize(e);
            }
            t.Commit(pe);

            Assert.AreEqual(15, pe.Load("Person").Count);
            Assert.AreEqual(10, pe.Load("Person", null, 1, 10).Count);
            Assert.AreEqual(10, pe.Load("Person", null, 2, 10).Count);
            Assert.AreEqual(10, pe.Load("Person", null, 3, 10).Count);
            Assert.AreEqual(10, pe.Load("Person", null, 4, 10).Count);
            Assert.AreEqual(10, pe.Load("Person", null, 5, 10).Count);
            Assert.AreEqual(10, pe.Load("Person", null, 6, 10).Count);
            Assert.AreEqual(9, pe.Load("Person", null, 7, 10).Count);
            Assert.AreEqual(8, pe.Load("Person", null, 8, 10).Count);
            Assert.AreEqual(7, pe.Load("Person", null, 9, 10).Count);
            Assert.AreEqual(6, pe.Load("Person", null, 10, 10).Count);
            Assert.AreEqual(5, pe.Load("Person", null, 11, 10).Count);
            Assert.AreEqual(4, pe.Load("Person", null, 12, 10).Count);
            Assert.AreEqual(3, pe.Load("Person", null, 13, 10).Count);
            Assert.AreEqual(2, pe.Load("Person", null, 14, 10).Count);
            Assert.AreEqual(1, pe.Load("Person", null, 15, 10).Count);
            Assert.AreEqual(0, pe.Load("Person", null, 16, 10).Count);
        }

        [TestMethod]
        public virtual void Composition()
        {
            //pe.InitializeRepository();

            Entity paloalto = new Entity("Address");
            paloalto.AddValue("City", "Palo Alto");

            Entity steve = new Entity("Person");
            steve.AddValue("Firstname", "Steve Jobs");
            steve.AddValue("Address", paloalto);

            Transaction t = new Transaction();
            t.Serialize(steve);
            t.Commit(pe);

            Entity p = (Entity)pe.Load("Person")[0];

            Assert.AreEqual(1, pe.Load("Person").Count);
            Assert.AreEqual(1, pe.Load("Address").Count);

            pe.LoadReference(p, new string[] { "Address" });

            EntitySet es = pe.Load("Person.Address");

            Assert.AreEqual(1, es.Count);

            t = new Transaction();
            t.Delete(steve);
            t.Commit(pe);

            Assert.AreEqual(0, pe.Load("Person").Count);
            Assert.AreEqual(0, pe.Load("Address").Count);
        }

        [TestMethod]
        public virtual void Composition2()
        {
            // a Person should not be deleted if its address is deleted

            //pe.InitializeRepository();

            Entity paloalto = new Entity("Address");
            paloalto.AddValue("City", "Palo Alto");

            Entity steve = new Entity("Person");
            steve.AddValue("Firstname", "Steve Jobs");
            steve.AddValue("Address", paloalto);

            Transaction t = new Transaction();
            t.Serialize(steve);
            t.Commit(pe);

            Entity p = (Entity)pe.Load("Person")[0];

            Assert.AreEqual(1, pe.Load("Person").Count);
            Assert.AreEqual(1, pe.Load("Address").Count);

            pe.LoadReference(p, new string[] { "Address" });

            EntitySet es = pe.Load("Person.Address");

            Assert.AreEqual(1, es.Count);

            t = new Transaction();
            t.Delete(paloalto);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load("Person").Count);
            Assert.AreEqual(0, pe.Load("Address").Count);
        }

        [TestMethod]
        public virtual void ReferenceInheritance()
        {
            //pe.InitializeRepository();

            Entity d1 = new Entity("Test:D");
            d1.AddValue("d", "d1");
            d1.Id = "d_1";

            Entity d2 = new Entity("Test:D_Sub");
            d2.AddValue("d", "d2");
            d2.AddValue("dp", "db1");
            d2.Id = "d_2";

            Entity d3 = new Entity("Test:D_Sub");
            d3.AddValue("d", "d3");
            d3.AddValue("dp", "db1");
            d3.Id = "d_3";

            Entity e = new Entity("Test:E");
            e.AddValue("e", "e1");
            e.Id = "e_1";

            Entity e2 = new Entity("Test:E");
            e2.AddValue("e", "e2");
            e2.Id = "e_2";

            Entity f = new Entity("Test:F");
            f.AddValue("e", "e2");
            f.AddValue("f", "f1");
            f.Id = "f_1";

            d1.AddValue("Refs", e);
            d1.AddValue("Refs", f);

            d2.AddValue("Refs", e2);

            Transaction t = new Transaction();
            t.Serialize(d1);
            t.Serialize(d2);
            t.Serialize(d3);
            t.Serialize(e2);
            t.Commit(pe);

            EntitySet es = pe.Load("Test:D");
            Assert.AreEqual(3, es.Count);

            es = pe.Load("Test:D.Refs");
            Assert.AreEqual(3, es.Count);

            es = pe.Load("Test:D[d = 'd1' or d = 'd2']");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("Test:D_Sub.Refs");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("Test:D[d = 'd1'].Refs");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("Test:D");
            pe.LoadReference(es, new string[] { "Refs" });

            es = pe.Load("Test:D[d > 'd1']");
            Assert.AreEqual(2, es.Count, "comparer < > used with strings");

            d1 = (Entity)pe.Load("Test:D[d = 'd1']")[0];
            Assert.IsNotNull(d1);

            pe.LoadReference(d1, new string[] { "Refs" });
            Assert.AreEqual(2, d1.GetEntitySet("Refs").Count);

            d1 = (Entity)pe.Load(string.Concat("Test:D[ count(Refs[id('", e.Id, "')]) > 0]"))[0];
            Assert.IsNotNull(d1);
            Assert.AreEqual("Test:D", d1.Type);
            Assert.AreEqual("d1", d1["d"]);

            es = pe.Load(string.Concat("Test:D[ count(Refs[id('", e.Id, "', '", f.Id, "')]) > 0]"));
            Assert.AreEqual(1, es.Count);

            es = pe.Load("Test:D[ exists(Refs) ]");
            Assert.AreEqual(2, es.Count);

            es = pe.Load(string.Concat("Test:D[ count(Refs[id('", e.Id, "')]) > 0]"));
            Assert.AreEqual(1, es.Count);
        }

        [TestMethod]
        public virtual void LinkedReferences()
        {
            //	x1.YRef = y2
            //	x1.YRef = y3
            //	y2.ZRef = z1

            //	x2.YRef = y1
            //	y1.ZRef = z2

            Entity x1 = new Entity("X");
            x1.AddValue("xvalue", "x1");
            x1.Id = "x_1";

            Entity x2 = new Entity("X");
            x2.AddValue("xvalue", "x2");
            x2.Id = "x_2";

            Entity x3 = new Entity("X");
            x3.AddValue("xvalue", "x3");
            x3.Id = "x_3";

            Entity x4 = new Entity("X");
            x4.AddValue("xvalue", "x4");
            x4.Id = "x_4";

            Entity y1 = new Entity("Y");
            y1.AddValue("yvalue", "y1");
            y1.Id = "y_1";

            Entity y2 = new Entity("Y");
            y2.AddValue("yvalue", "y2");
            y2.Id = "y_2";

            Entity y3 = new Entity("Y");
            y3.AddValue("yvalue", "y3");
            y3.Id = "y_3";

            Entity z1 = new Entity("Z");
            z1.AddValue("zvalue", "z1");
            z1.Id = "z_1";

            Entity z2 = new Entity("Z");
            z2.AddValue("zvalue", "z2");
            z2.Id = "z_2";

            x1.AddValue("YRef", y2);
            x1.AddValue("YRef", y3);
            x2.AddValue("YRef", y1);

            y1.AddValue("ZRef", z2);
            y2.AddValue("ZRef", z1);

            Transaction t = new Transaction();
            t.Serialize(x1);
            t.Serialize(x2);
            t.Serialize(x3);
            t.Serialize(x4);
            t.Commit(pe);

            Trace.Listeners.Add(new TextWriterTraceListener("c:\\nunittrace.sql"));

            EntitySet es = pe.Load("X[ ( count(YRef) = 2 ) or ( count(YRef) = 1 ) ]");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("X[ exists(YRef[count(ZRef) = 1]) ]");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("X");
            Assert.AreEqual(4, es.Count);

            es = pe.Load("X[exists(YRef[yvalue = 'y2'])]");
            Assert.AreEqual(1, es.Count);

            Trace.Close();

            es = pe.Load("X.YRef");
            Assert.AreEqual(3, es.Count);

            foreach (Entity e in es)
                Assert.AreEqual("Y", e.Type);

            es = pe.Load("X[count(YRef) = 2]");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("X[ max(YRef.yvalue) = 'y3' ]");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("Y.ZRef");
            Assert.AreEqual(2, es.Count);

            foreach (Entity e in es)
                Assert.AreEqual("Z", e.Type);

            es = pe.Load("X.YRef.ZRef");
            Assert.AreEqual(2, es.Count);

            foreach (Entity e in es)
                Assert.AreEqual("Z", e.Type);

            es = pe.Load("X[xvalue = 'x2'].YRef.ZRef");
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("Z", ((Entity)es[0]).Type);

            z2 = (Entity)pe.Load("X.YRef[yvalue = 'y1'].ZRef")[0];
            Assert.AreEqual("z2", z2["zvalue"]);

            z1 = (Entity)pe.Load("X[xvalue = 'x1'].YRef.ZRef[zvalue = 'z1']")[0];
            Assert.AreEqual("z1", z1["zvalue"]);

            es = pe.Load("X[ exists(YRef[yvalue = 'toto']) ]");
            Assert.AreEqual(0, es.Count);

            es = pe.Load("X[ exists(YRef[yvalue = 'y1']) ]");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("X[ exists(YRef) ]");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("X[ exists(YRef.ZRef) ]");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("X[id('x_1')].YRef[exists(ZRef[id('z_1')])]");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("X[ exists(YRef[ exists(ZRef)] ) ]");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("X[ exists(YRef.ZRef[zvalue = 'z2']) ]");

            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("x2", ((Entity)es[0])["xvalue"]);
        }

        [TestMethod]
        public virtual void AbstractClass()
        {
            Entity b = new Entity("B");
            b.AddValue("a", "b : value_a");
            b.AddValue("b", "b : value_b");

            Entity c = new Entity("C");
            c.AddValue("a", "c : value_a");
            c.AddValue("c", "c : value_c");

            Transaction t = new Transaction();
            t.Serialize(b);
            t.Serialize(c);
            t.Commit(pe);

            Assert.AreEqual(2, pe.Load("A").Count);
            Assert.AreEqual(1, pe.Load("B").Count);
            Assert.AreEqual(1, pe.Load("C").Count);

            b = (Entity)pe.Load("B")[0];

            Assert.AreEqual(2, b.EntityEntries.Count);
            Assert.AreEqual("b : value_a", b["a"]);
            Assert.AreEqual("b : value_b", b["b"]);

            c = (Entity)pe.Load("C")[0];

            Assert.AreEqual(2, c.EntityEntries.Count);
            Assert.AreEqual("c : value_a", c["a"]);
            Assert.AreEqual("c : value_c", c["c"]);
        }

        [TestMethod]
        public virtual void OneToMany()
        {
            Entity u1 = new Entity("U");
            u1.AddValue("u", "value : u1");

            Entity u2 = new Entity("U");
            u2.AddValue("u", "value : u2");

            Entity v1 = new Entity("V");
            v1.AddValue("v", "value : v1");

            Entity v2 = new Entity("V");
            v2.AddValue("v", "value : v2");

            Entity v3 = new Entity("V");
            v3.AddValue("v", "value : v3");

            u1.AddValue("VRef", v1);
            u1.AddValue("VRef", v3);

            u2.AddValue("VRef", v2);

            Transaction t = new Transaction();
            t.Serialize(u1);
            t.Serialize(u2);
            t.Commit(pe);

            EntitySet es = pe.Load("U[u = 'value : u1'].VRef");

            Assert.AreEqual(2, es.Count);

            es = pe.Load("U[u = 'value : u1'].VRef[v = 'value : v1']");

            Assert.AreEqual(1, es.Count);
            Assert.AreEqual(v1.Id, ((Entity)es[0]).Id);

            es = pe.Load("U[u = 'value : u1'].VRef[v = 'value : v3']");

            Assert.AreEqual(1, es.Count);
            Assert.AreEqual(v3.Id, ((Entity)es[0]).Id);
        }

        [TestMethod]
        public virtual void Aggregation()
        {
            Entity u = new Entity("U");
            u.AddValue("u", "value : u");

            Entity v = new Entity("V");
            v.AddValue("v", "value : v");

            u.AddValue("VRef", v);

            Transaction t = new Transaction();
            t.Serialize(u);
            t.Commit(pe);

            u = (Entity)pe.Load("U")[0];
            Assert.AreEqual("value : u", u["u"]);
            pe.LoadReference(u, new string[] { "VRef" });

            v = (Entity)u.GetEntitySet("VRef")[0];
            Assert.AreEqual("value : v", v["v"]);

            t = new Transaction();
            t.Delete(u);
            t.Commit(pe);

            EntitySet es = pe.Load("U");
            Assert.AreEqual(0, es.Count);

            es = pe.Load("V");
            Assert.AreEqual(0, es.Count);
        }

        [TestMethod]
        public virtual void LoadAttributes()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Sébastien");
            p1.AddValue("Age", 26);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            Entity e1 = pe.Load("Person[Firstname = 'Sébastien']")[0];
            Assert.AreEqual(2, e1.EntityEntries.Count);

            e1 = pe.Load("Person[Firstname = 'Sébastien']", null)[0];
            Assert.AreEqual(0, e1.EntityEntries.Count);

            e1 = pe.Load("Person[Firstname = 'Sébastien']", new string[0])[0];
            Assert.AreEqual(2, e1.EntityEntries.Count);

            e1 = pe.Load("Person[Firstname = 'Sébastien']", new string[] { "Firstname" })[0];
            Assert.AreEqual(1, e1.EntityEntries.Count);
            Assert.AreEqual("Sébastien", e1["Firstname"].ToString());

            e1 = pe.Load("Person[Firstname = 'Sébastien']", new string[] { "Firstname", "Age" })[0];
            Assert.AreEqual(2, e1.EntityEntries.Count);
            Assert.AreEqual("Sébastien", e1["Firstname"].ToString());
            Assert.AreEqual(26, e1.GetInt32("Age"));
        }

        public virtual void References4()
        {
            //pe.InitializeRepository();

            Entity aff = new Entity("Affaire");
            aff.AddValue("name", "aff1");
            aff.AddValue("typeaffaire", "typeA");
            aff.Id = "A1";

            Entity aff2 = new Entity("Affaire");
            aff2.AddValue("name", "aff2");
            aff2.AddValue("typeaffaire", "typeA");
            aff2.Id = "A2";

            Entity add = new Entity("Site");
            add.AddValue("city", "new york");
            add.AddValue("description", "an other site ...");
            add.Id = "S1";

            Entity add2 = new Entity("SiteLivraison");
            add2.AddValue("city", "chicago");
            add2.AddValue("descriptionsite", "a site ...");
            add2.Id = "S2";

            aff.AddValue("MonAddressLivraison", add);
            aff2.AddValue("MonAddressLivraison", add2);

            Transaction t = new Transaction();
            t.Serialize(aff);
            t.Serialize(aff2);
            t.Commit(pe);

            Entity e = pe.Load("Affaire[name = 'aff1']")[0];
            Assert.IsNotNull(e);

            pe.LoadReference(e, new string[] { "MonAddressLivraison" });

            Assert.AreEqual(1, e.GetEntitySet("MonAddressLivraison").Count);

            e = pe.Load("Affaire[name = 'aff2']")[0];
            Assert.IsNotNull(e);

            pe.LoadReference(e, new string[] { "MonAddressLivraison" });

            Assert.AreEqual(1, e.GetEntitySet("MonAddressLivraison").Count);

            EntitySet es = pe.Load("Commande.MonAddressLivraison");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("Affaire.MonAddressLivraison");
            Assert.AreEqual(2, es.Count);
        }

        public virtual void Reference5()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "bill");

            Entity p2 = new Entity("Employee");
            p2.AddValue("Firstname", "steve");

            Entity p3 = new Entity("Worker");
            p3.AddValue("Firstname", "mark");

            Entity p4 = new Entity("Secretary");
            p4.AddValue("Firstname", "john");

            Entity p5 = new Entity("Employee");
            p5.AddValue("Firstname", "reggie");

            p1.AddValue("Partners", p2);
            p1.AddValue("Partners", p3);
            p1.AddValue("Partners", p4);

            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p5);
            t.Commit(pe);

            DateTime start = DateTime.Now;

            EntitySet es = pe.Load("Person.Partners");
            Assert.AreEqual(3, es.Count);

            es = pe.Load("Person.Partners.Partners");
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("Worker", es[0].Type);
            Assert.AreEqual("mark", es[0]["Firstname"]);

            es = pe.Load("Person[exists(Partners)]");
            Assert.AreEqual(2, es.Count);

            es = pe.Load("Person[exists(Partners.Partners)]");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("Person[exists(Partners.Partners) and Firstname = 'bill']");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("Employee[exists(Partners)]");
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("Employee", es[0].Type);

            es = pe.Load("Person[count(Partners) = 0 and Firstname = 'reggie']");
            Assert.AreEqual(1, es.Count);
            Assert.AreEqual("Employee", es[0].Type);

            DateTime end = DateTime.Now;

            TimeSpan ts = end - start;
            Console.WriteLine(ts.Seconds);
        }

        [TestMethod]
        public virtual void LoadWithId()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Laurent");
            p1.AddValue("Age", 1);
            p1.Id = "Laurent";

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Fabien");
            p2.AddValue("Age", 2);
            p2.Id = "Fabien";

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Sébastien");
            p3.AddValue("Age", 3);
            p3.Id = "Sébastien";

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pe);

            Entity p = pe.LoadWithId("Person", "Laurent");
            Assert.AreEqual("Laurent", p.GetString("Firstname"));

            p = pe.LoadWithId("Person", new string[] { "Fabien" }, null)[0];
            Assert.AreEqual(0, p.EntityEntries.Count);
            Assert.AreEqual("Fabien", p.Id);

            p = pe.LoadWithId("Person", new string[] { "Sébastien" }, new string[] { "Age" })[0];
            Assert.AreEqual(3, p.GetInt32("Age"));

            // in case of cache engine, start with an empty cache
            pe.Initialize();

            p = pe.LoadWithId("Person", "Fabien");
            Assert.AreEqual("Fabien", p.GetString("Firstname"));

            p = pe.LoadWithId("Person", new string[] { "Laurent" }, null)[0];
            Assert.AreEqual("Laurent", p.Id);
            Assert.AreEqual(0, p.EntityEntries.Count);

            p = pe.LoadWithId("Person", new string[] { "Sébastien" }, new string[] { "Firstname" })[0];
            Assert.AreEqual("Sébastien", p.GetString("Firstname"));
            Assert.AreEqual(1, p.EntityEntries.Count);
        }

        [TestMethod]
        public virtual void QuoteId()
        {
            Entity x1 = new Entity("X");
            x1.AddValue("xvalue", "x1");
            x1.Id = "x'i'1";

            Transaction t = new Transaction();
            t.Serialize(x1);
            t.Commit(pe);

            x1 = pe.LoadWithId("X", "x'i'1");
            Assert.IsNotNull(x1);

            x1 = pe.Load(@"X[id('x\'i\'1')]")[0];
            Assert.IsNotNull(x1);
        }

        [TestMethod]
        public virtual void LoadScalarInheritance()
        {
            pe.InitializeRepository();

            Entity bill = new Entity("Employee");
            bill.AddValue("Firstname", "Bill Gates");
            bill.AddValue("Salary", 99999d);

            Entity steve = new Entity("Person");
            steve.AddValue("Firstname", "Steve Jobs");

            Transaction t = new Transaction();
            t.Serialize(bill);
            t.Serialize(steve);
            t.Commit(pe);

            Assert.AreEqual(2, pe.Load("Person").Count);
            Assert.AreEqual(1, pe.Load("Employee").Count);

            Assert.AreEqual(99999d, pe.LoadScalar("max(Employee.Salary)"));

        }

        [TestMethod]
        public virtual void LoadScalar()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Tintin");
            p1.AddValue("Age", 10);

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Tintin");
            p2.AddValue("Age", 20);

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Haddock");
            p3.AddValue("Age", 30);

            Entity p4 = new Entity("Person");
            p4.AddValue("Firstname", "Pr Calculus");
            p4.AddValue("Age", 60);

            p1.AddValue("Partners", p3);
            p1.AddValue("Partners", p4);
            p3.AddValue("Partners", p2);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Serialize(p4);
            t.Commit(pe);

            Assert.AreEqual(4, pe.LoadScalar("count(Person)"));
            Assert.AreEqual(2, pe.LoadScalar("count(Person[Firstname = 'Tintin'])"));
            Assert.AreEqual(2, pe.LoadScalar("count(Person[Firstname = 'Tintin']) + 2 - 2"));                                   // not supported by Ms Access
            Assert.AreEqual(3, pe.LoadScalar("count(Person[Firstname = 'Tintin']) + count(Person[Firstname = 'Haddock'])"));    // not supported by Ms Access

            Assert.AreEqual(120 / 4, pe.LoadScalar("sum(Person.Age) / count(Person)"));                                         // not supported by Ms Access
            Assert.AreEqual(30d, pe.LoadScalar("avg(Person.Age)"));
            Assert.AreEqual(10, pe.LoadScalar("min(Person.Age)"));
            Assert.AreEqual(60, pe.LoadScalar("max(Person.Age)"));

            Assert.AreEqual(2, pe.LoadScalar("count(Person[Firstname = 'Tintin'].Partners)"));
            Assert.AreEqual(2, pe.LoadScalar("count(Person[ exists(Partners)])"));
            Assert.AreEqual(3, pe.LoadScalar("count(Person.Partners)"));

            Assert.AreEqual(Math.Round((double)((double)(60 + 30 + 20) / (double)3), 10), Math.Round(Convert.ToDouble(pe.LoadScalar("avg(Person.Partners.Age)")), 10));
            Assert.AreEqual(20, pe.LoadScalar("min(Person.Partners.Age)"));
            Assert.AreEqual(60, pe.LoadScalar("max(Person.Partners.Age)"));

            // opath that matchs no entities
            Assert.AreEqual(0, pe.LoadScalar("count(Person[Firstname = 'Snowy'])"));
            object res = pe.LoadScalar("avg(Person[Firstname = 'Snowy'].Age)");
            res = pe.LoadScalar("min(Person[Firstname = 'Snowy'].Age)");
            res = pe.LoadScalar("max(Person[Firstname = 'Snowy'].Age)");
            res = pe.LoadScalar("sum(Person[Firstname = 'Snowy'].Age)");

            Assert.AreEqual(1, pe.LoadScalar("count(Person[Firstname = 'Tintin'].Partners.Partners)"), "query can be too long according to inheritance strategy");
        }

        [TestMethod]
        public virtual void LoadScalarType()
        {
            //pe.InitializeRepository();

            Entity e1 = new Entity("Person");
            e1.AddValue("Firstname", "e1");

            Entity e2 = new Entity("Person");
            e2.AddValue("Firstname", "e2");

            Transaction t = new Transaction();
            t.Serialize(e1);
            t.Serialize(e2);
            t.Commit(pe);

            object o = pe.LoadScalar("count(Person)");

            Assert.AreEqual(typeof(int), o.GetType());
        }

        [TestMethod]
        public virtual void LoadWithQuerySort()
        {
            // one field
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.Id = "1";
            p1.AddValue("Firstname", "p01");
            p1.AddValue("Age", 1);
            p1.AddValue("Acceleration", 1.2);

            Entity p2 = new Entity("Person");
            p2.Id = "3";
            p2.AddValue("Firstname", "p02");
            p2.AddValue("Age", 2);
            p2.AddValue("Acceleration", 2.2);

            Entity p3 = new Entity("Person");
            p3.Id = "2";
            p3.AddValue("Firstname", "p02");
            p3.AddValue("Age", 1);
            p3.AddValue("Acceleration", 0);

            Entity p4 = new Entity("Person");
            p4.Id = "4";
            p4.AddValue("Firstname", "p04");
            p4.AddValue("Age", 3);
            p4.AddValue("Acceleration", 4.2);


            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Serialize(p4);
            t.Commit(pe);

            EntitySet results = pe.Load("Person[Firstname ^ 'p']", "Firstname", 1, 0);

            Assert.AreEqual(4, results.Count);
            Assert.AreEqual("p01", results[0]["Firstname"]);
            Assert.AreEqual("p02", results[1]["Firstname"]);
            Assert.AreEqual("p02", results[2]["Firstname"]);
            Assert.AreEqual("p04", results[3]["Firstname"]);

            results = pe.Load("Person", "Firstname desc", 1, 0);

            Assert.AreEqual(4, results.Count);
            Assert.AreEqual("p04", results[0]["Firstname"]);
            Assert.AreEqual("p02", results[1]["Firstname"]);
            Assert.AreEqual("p02", results[2]["Firstname"]);
            Assert.AreEqual("p01", results[3]["Firstname"]);

            results = pe.Load("Person", "Id desc", 1, 0);

            Assert.AreEqual(4, results.Count);
            Assert.AreEqual("4", results[0].Id);
            Assert.AreEqual("3", results[1].Id);
            Assert.AreEqual("2", results[2].Id);
            Assert.AreEqual("1", results[3].Id);

            // two fields
            results = pe.Load("Person", "Firstname, Age", 1, 0);

            Assert.AreEqual("1", results[0].Id);
            Assert.AreEqual("2", results[1].Id);
            Assert.AreEqual("3", results[2].Id);
            Assert.AreEqual("4", results[3].Id);

            results = pe.Load("Person", "Firstname desc, Age desc", 1, 0);

            Assert.AreEqual("4", results[0].Id);
            Assert.AreEqual("3", results[1].Id);
            Assert.AreEqual("2", results[2].Id);
            Assert.AreEqual("1", results[3].Id);

            results = pe.Load("Person", "Id desc, Firstname asc ", 1, 0);

            Assert.AreEqual("4", results[0].Id);
            Assert.AreEqual("3", results[1].Id);
            Assert.AreEqual("2", results[2].Id);
            Assert.AreEqual("1", results[3].Id);

            results = pe.Load("Person", "Firstname, Id desc", 1, 0);

            Assert.AreEqual("1", results[0].Id);
            Assert.AreEqual("3", results[1].Id);
            Assert.AreEqual("2", results[2].Id);
            Assert.AreEqual("4", results[3].Id);


            Entity b1 = new Entity("Person");
            b1.Id = "10";
            b1.AddValue("Firstname", "b10");
            b1.AddValue("Age", 10);
            b1.AddValue("Acceleration", 0);

            Entity b2 = new Entity("Person");
            b2.Id = "20";
            b2.AddValue("Firstname", "b10");
            b2.AddValue("Age", 20);
            b2.AddValue("Acceleration", 0);

            Entity b3 = new Entity("Person");
            b3.Id = "30";
            b3.AddValue("Firstname", "b30");
            b3.AddValue("Age", 30);
            b3.AddValue("Acceleration", 0);

            p1.AddValue("Brother", b1);
            p2.AddValue("Brother", b2);
            p3.AddValue("Brother", b3);


            t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pe);


            results = pe.Load("Person[Firstname ^ 'p'].Brother", "Firstname, Age desc", 1, 0);

            Assert.AreEqual("20", results[0].Id);
            Assert.AreEqual("10", results[1].Id);
            Assert.AreEqual("30", results[2].Id);

            results = pe.Load("Person[Firstname ^ 'p'].Brother", "Firstname desc, Age", 1, 0);

            Assert.AreEqual("30", results[0].Id);
            Assert.AreEqual("10", results[1].Id);
            Assert.AreEqual("20", results[2].Id);

            results = pe.Load("Person", "Acceleration desc", 1, 3);

            Assert.AreEqual(3, results.Count);
            Assert.AreEqual("4", results[0].Id);
            Assert.AreEqual("3", results[1].Id);
            Assert.AreEqual("1", results[2].Id);

            // sort with a non existing attribute for one item
            results = pe.Load("Person[ exists(Brother[isNull(Lastname)])]", "Acceleration desc", 1, 3);

            Assert.AreEqual(3, results.Count, "sort with a non existing attribute for one item");
            Assert.AreEqual("3", results[0].Id);
            Assert.AreEqual("1", results[1].Id);
            Assert.AreEqual("2", results[2].Id);
        }

        [TestMethod]
        public virtual void Boolean()
        {
            //pe.InitializeRepository();

            Entity v1 = new Entity("ValueNamed");
            v1.AddValue("Name", "v1");
            v1.AddValue("IsValueType", false);
            v1.AddValue("ValueType", "Int");

            Transaction t = new Transaction();
            t.Serialize(v1);
            t.Commit(pe);

            EntitySet es = pe.Load("ValueNamed");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("ValueNamed[IsValueType = false]");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("ValueNamed[IsValueType = true]");
            Assert.AreEqual(0, es.Count);

            es = pe.Load("ValueNamed[IsValueType]");
            Assert.AreEqual(0, es.Count);

            es = pe.Load("ValueNamed[not (IsValueType)]");
            Assert.AreEqual(1, es.Count);

            es = pe.Load("ValueNamed[IsValueType and Name = 'v1']");
            Assert.AreEqual(0, es.Count);

        }

        [TestMethod]
        public virtual void LoadWithQueryMinMax()
        {
            //pe.InitializeRepository();

            EntitySet es = new EntitySet();

            for (int i = 1; i <= 50; i++)
            {
                Entity p = new Entity("Person");
                p.AddValue("Firstname", "p" + i.ToString("00"));
                es.Add(p);
            }

            Transaction t = new Transaction();
            t.Serialize(es);
            t.Commit(pe);

            EntitySet results = null;


            // test arguments validity
            bool exceptionOccured = false;

            try { results = pe.Load("Person", "Firstname", 0, 100); }
            catch { exceptionOccured = true; }

            if (!exceptionOccured)
                Assert.Fail("first argument exception");

            exceptionOccured = false;

            try { results = pe.Load("Person", "Firstname", 1, -1); }
            catch { exceptionOccured = true; }

            if (!exceptionOccured)
                Assert.Fail("max argument exception");

            results = pe.Load("Person", "Firstname", 1, 100);

            Assert.AreEqual(50, results.Count);

            results = pe.Load("Person", "Firstname", 10, 21);

            Assert.AreEqual(21, results.Count);
            Assert.AreEqual("p10", results[0]["Firstname"]);
            Assert.AreEqual("p20", results[10]["Firstname"]);
            Assert.AreEqual("p30", results[20]["Firstname"]);

            results = pe.Load("Person", "Firstname", 40, 11);

            Assert.AreEqual(11, results.Count);
            Assert.AreEqual("p40", results[0]["Firstname"]);
            Assert.AreEqual("p50", results[10]["Firstname"]);

            results = pe.Load("Person", "Firstname", 50, 1);

            Assert.AreEqual(1, results.Count);
            Assert.AreEqual("p50", results[0]["Firstname"]);

            results = pe.Load("Person", "Firstname", 10, 41);

            Assert.AreEqual(41, results.Count);
            Assert.AreEqual("p10", results[0]["Firstname"]);
            Assert.AreEqual("p20", results[10]["Firstname"]);
            Assert.AreEqual("p50", results[40]["Firstname"]);

            // test if no results are return by the opath
            results = pe.Load("Person[Firstname = 'toto']", "Firstname", 10, 41);

            Assert.AreEqual(0, results.Count);
        }

        [TestMethod]
        public virtual void DeleteReference1()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Fabien");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Sébastien");

            p1.AddValue("Partners", p2);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            p1 = pe.Load("Person[Firstname = 'Fabien']")[0];
            pe.LoadReference(p1, new string[] { "Partners" });
            Assert.AreEqual(1, p1.GetEntitySet("Partners").Count);

            p1.DeleteElement("Partners", p1.GetEntitySet("Partners")[0]);

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            p1 = pe.Load("Person[Firstname = 'Fabien']")[0];
            pe.LoadReference(p1, new string[] { "Partners" });
            Assert.AreEqual(0, p1.GetEntitySet("Partners").Count);

        }

        [TestMethod]
        public virtual void ReferenceIntegrity()
        {
            // This test has to be checked visually by verifying that the relationships with the deleted element are deleted

            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Fabien");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Sébastien");

            p1.AddValue("Partners", p2);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            p2 = pe.Load("Person[Firstname = 'Fabien']")[0];

            t = new Transaction();
            t.Delete(p2);
            t.Commit(pe);
        }

        [TestMethod]
        public virtual void ReferenceIntegrity2()
        {
            // This test has to be checked visually by verifying that the relationships with the deleted element are deleted

            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Fabien");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Sébastien");

            p1.AddValue("Partners", p2);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            p2 = pe.Load("Person[Firstname = 'Sébastien']")[0];

            t = new Transaction();
            t.Delete(p2);
            t.Commit(pe);
        }

        [TestMethod]
        public virtual void DeleteReference2()
        {
            //  Delete reference (Foreign key)

            //pe.InitializeRepository();

            Entity u = new Entity("U");
            u.AddValue("u", "value : u1");

            Entity v1 = new Entity("V");
            v1.AddValue("v", "value : v1");

            Entity v2 = new Entity("V");
            v2.AddValue("v", "value : v2");

            Entity v3 = new Entity("V");
            v3.AddValue("v", "value : v3");

            u.AddValue("VRef", v1);
            u.AddValue("VRef", v2);
            u.AddValue("VRef", v3);

            Transaction t = new Transaction();
            t.Serialize(u);
            t.Commit(pe);

            u = pe.Load("U")[0];

            pe.LoadReference(u, new string[] { "VRef" });
            Assert.AreEqual(3, u.GetEntitySet("VRef").Count);

            u.DeleteElement("VRef", u.GetEntitySet("VRef")[0]);

            t = new Transaction();
            t.Serialize(u);
            t.Commit(pe);

            u = pe.Load("U")[0];

            pe.LoadReference(u, new string[] { "VRef" });
            Assert.AreEqual(2, u.GetEntitySet("VRef").Count);

            u = pe.Load("U")[0];

            pe.LoadReference(u, new string[] { "VRef" });

            u.DeleteElement("VRef");

            t = new Transaction();
            t.Serialize(u);
            t.Commit(pe);

            u = pe.Load("U")[0];

            pe.LoadReference(u, new string[] { "VRef" });
            Assert.AreEqual(0, u.GetEntitySet("VRef").Count);
        }

        [TestMethod]
        public virtual void ManyToOneUpdate()
        {
            //pe.InitializeRepository();

            Entity s1 = new Entity("Student");
            s1.AddValue("Name", "bill");

            Entity s2 = new Entity("Student");
            s2.AddValue("Name", "Steve");

            Entity s3 = new Entity("Student");
            s3.AddValue("Name", "John");

            Entity s4 = new Entity("Student");
            s4.AddValue("Name", "Mark");

            Entity c1 = new Entity("Course");
            c1.AddValue("Subject", "Data Processing");

            Entity c2 = new Entity("Course");
            c2.AddValue("Subject", "Mathematics");

            s1.AddValue("MyCourse", c1);
            s2.AddValue("MyCourse", c1);
            s3.AddValue("MyCourse", c2);

            Transaction t = new Transaction();
            t.Serialize(s1);
            t.Serialize(s2);
            t.Serialize(s3);
            t.Serialize(s4);
            t.Commit(pe);

            Entity parent = pe.Load("Student[Name = 'bill']")[0];
            Assert.IsNotNull(parent);

            Entity child = pe.Load("Course[Subject = 'Mathematics']")[0];
            Assert.IsNotNull(child);

            parent["Name"] = "Bill";
            parent["MyCourse"] = child;

            t = new Transaction();
            t.Serialize(parent);
            t.Commit(pe);

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Bill");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Steve");

            Entity t1 = new Entity("Thing");
            t1.AddValue("Firstname", "John");

            Entity t2 = new Entity("Thing");
            t2.AddValue("Firstname", "Mark");

            p1.AddValue("ToMany", t1);
            p1.AddValue("ToMany", t2);

            t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Commit(pe);

            t = new Transaction();
            t.Delete(p1);
            t.Commit(pe);

            EntitySet things = pe.Load("Person[exists(ToMany[Firstname = 'John'])]");
            Assert.IsNotNull(things);
            Assert.AreEqual(0, things.Count);

            EntitySet people = pe.Load("Person[Firstname='Bill']");
            Assert.IsNotNull(people);
            Assert.AreEqual(0, people.Count);
        }

        //[TestMethod]
        //public virtual void InheritanceMultiBranch()
        //{
        //    pe.InitializeRepository();

        //    Entity bill = new Entity("Employee");
        //    bill.AddValue("Firstname", "Bill Gates");
        //    bill.AddValue("Salary", 99999);
        //    bill.AddValue("DailyCost", 1000);

        //    Entity kevin = new Entity("Teenager");
        //    kevin.AddValue("Firstname", "Kevin");
        //    kevin.AddValue("PocketMoney", 40);
        //    kevin.AddValue("DailyCost", 80);

        //    Entity papy = new Entity("Pensioner");
        //    papy.AddValue("Firstname", "Tim");
        //    papy.AddValue("Salary", 1);
        //    papy.AddValue("DailyCost", 200);

        //    Transaction t = new Transaction();
        //    t.Serialize(bill);
        //    t.Serialize(kevin);
        //    t.Serialize(papy);
        //    t.Commit(pe);

        //    Assert.AreEqual(3, pe.Load("Person[Firstname ~ 'i']").Count);

        //    Entity eBill = pe.Load("Employee[Firstname ~ 'i'])")[0];
        //    Assert.AreEqual((double)99999, eBill.GetDouble("Salary"));

        //    Entity eKevin = pe.Load("Teenager[Firstname ~ 'i'])")[0];
        //    Assert.AreEqual((double)40, eKevin.GetDouble("PocketMoney"));

        //    Entity ePapy = pe.Load("Pensioner[Firstname ~ 'i'])")[0];
        //    Assert.AreEqual((double)1, ePapy.GetDouble("Salary"));

        //    EntitySet people = pe.Load("Person", "DailyCost desc", 1, 0);
        //    Assert.AreEqual("Bill Gates", people[0].GetString("Firstname"));
        //    Assert.AreEqual("Tim", people[1].GetString("Firstname"));
        //    Assert.AreEqual("Kevin", people[2].GetString("Firstname"));
        //}

        [TestMethod]
        public virtual void InheritanceMultiBranch()
        {
            //pe.InitializeRepository();

            Entity circle = new Entity("Circle");
            circle.AddValue("Name", "circle");
            circle.AddValue("Position", 1);
            circle.AddValue("Size", 10);

            Entity line = new Entity("Line");
            line.AddValue("Name", "line");
            line.AddValue("Position", 2);
            line.AddValue("PositionEnd", 20);

            Entity square = new Entity("Square");
            square.AddValue("Name", "square");
            square.AddValue("Position", 3);
            square.AddValue("Size", 10);

            Entity rectangle = new Entity("Rectangle");
            rectangle.AddValue("Name", "rectangle");
            rectangle.AddValue("Position", 4);
            rectangle.AddValue("Size", 60);
            rectangle.AddValue("Height", 30);

            Entity figure = new Entity("Figure");
            figure.AddValue("Name", "home");
            figure.AddValue("Position", 5);
            figure.AddValue("Shapes", rectangle);
            figure.AddValue("Shapes", line);

            Entity plot = new Entity("Shape");
            plot.AddValue("Name", "plot");
            plot.AddValue("Position", 6);

            Transaction t = new Transaction();
            t.Serialize(circle);
            t.Serialize(line);
            t.Serialize(square);
            t.Serialize(rectangle);
            t.Serialize(figure);
            t.Serialize(plot);
            t.Commit(pe);

            Assert.AreEqual(6, pe.Load("Shape[Position > 0]").Count);

            Entity firstShape = pe.Load("Shape", "Position", 1, 0)[0];
            Assert.AreEqual("circle", firstShape["Name"]);
            Assert.AreEqual(10, firstShape["Size"]);

            Entity eCircle = pe.Load("Circle[Position > 0]")[0];
            Assert.AreEqual(10, eCircle.GetInt32("Size"));

            Entity eLine = pe.Load("Line")[0];

            Assert.AreEqual("line", eLine.GetString("Name"));
            Assert.AreEqual(20, eLine.GetInt32("PositionEnd"));

            Assert.AreEqual(2, pe.Load("Square[Position > 0]").Count);

            Entity eSquare = pe.Load("Square[Position > 0]", "Position", 1, 0)[0];
            Assert.AreEqual("square", eSquare.GetString("Name"));
            Assert.AreEqual(10, eSquare.GetInt32("Size"));

            Entity eRect = pe.Load("Rectangle[Height > 0]")[0];
            Assert.AreEqual("rectangle", eRect.GetString("Name"));
            Assert.AreEqual(4, eRect.GetInt32("Position"));
            Assert.AreEqual(60, eRect.GetInt32("Size"));
            Assert.AreEqual(30, eRect.GetInt32("Height"));

            Entity eFig = pe.Load("Figure[ count(Shapes) > 0]")[0];
            Assert.AreEqual("home", eFig.GetString("Name"));

            Entity eFigLine = pe.Load("Figure[ count(Shapes) > 0].Shapes[Position = 2]")[0];
            Assert.AreEqual("line", eFigLine.GetString("Name"));

            EntitySet shapes = pe.Load("Shape", "Position", 1, 0);
            Assert.AreEqual("circle", shapes[0].GetString("Name"));
            Assert.AreEqual("line", shapes[1].GetString("Name"));
            Assert.AreEqual("square", shapes[2].GetString("Name"));
            Assert.AreEqual("rectangle", shapes[3].GetString("Name"));
            Assert.AreEqual("home", shapes[4].GetString("Name"));
            Assert.AreEqual("plot", shapes[5].GetString("Name"));

            Assert.AreEqual(1 + 2 + 3 + 4 + 5 + 6, pe.LoadScalar("sum(Shape.Position)"));

        }

        private ArrayList _exceptions;

        [TestMethod]
        public virtual void MultiThreading()
        {

            // Repeats the tests n times
            for (int cpt = 0; cpt < 20; cpt++)
            {
                int NBTHREADS = 30;
                _exceptions = new ArrayList();
                Thread[] threads = new Thread[NBTHREADS];

                #region Initialization
                pe.InitializeRepository();

                Entity p1 = new Entity("Person");
                p1.AddValue("Firstname", "Fabien");
                p1.Id = "p1";

                Entity p2 = new Entity("Person");
                p2.AddValue("Firstname", "Laurent");
                p2.Id = "p2";

                Entity p3 = new Entity("Person");
                p3.AddValue("Firstname", "Séb");
                p3.Id = "p3";

                Entity a1 = new Entity("Address");
                a1.AddValue("City", "Mulhouse");
                a1.Id = "a1";

                Entity a2 = new Entity("Address");
                a2.AddValue("City", "Hegenheim");
                a2.Id = "a2";

                p1.AddValue("Address", a2);
                p1.AddValue("Partners", p2);
                p2.AddValue("Address", a1);
                p3.AddValue("Address", a1);

                Transaction t = new Transaction();
                t.Serialize(p1);
                t.Serialize(p2);
                t.Serialize(p3);
                t.Commit(pe);
                #endregion

                // Starts threads
                for (int i = 0; i < NBTHREADS; i++)
                {
                    Thread thread = new Thread(new ThreadStart(ReaderThread));
                    thread.Start();
                    threads[i] = thread;
                }

                // Waits for end of threads
                bool running = true;
                while (running)
                {
                    Thread.Sleep(100);
                    running = false;
                    for (int i = 0; i < NBTHREADS; i++)
                    {
                        if (threads[i].ThreadState == System.Threading.ThreadState.Running)
                            running = true;
                    }
                }

                if (_exceptions.Count > 0)
                {
                    Console.WriteLine(((Exception)_exceptions[0]).StackTrace);
                    Assert.Fail(((Exception)_exceptions[0]).Message);
                }
            }
        }

        private void ReaderThread()
        {
            try
            {
                // Each thread must have his own PE as it is not ThreadSafe
                IPersistenceEngine pe = pef.CreatePersistenceEngine();

                EntitySet es = pe.Load("Person");
                Assert.AreEqual(3, es.Count);

                foreach (Entity e in es)
                    Assert.AreEqual(0, e.GetEntitySet("Address").Count);

                pe.LoadReference(es, new string[] { "Address" });

                foreach (Entity e in es)
                    Assert.AreEqual(1, e.GetEntitySet("Address").Count);

                Entity p1 = pe.Load("Person[exists(Address[id('a2')]) and exists(Partners[Firstname = 'Laurent']) and Firstname = 'Fabien' ]")[0];

                Assert.IsNotNull(p1);
                Assert.AreEqual("Fabien", p1["Firstname"]);

                pe.LoadReference(p1, new string[] { "Address", "Partners" });

                Assert.AreEqual("Hegenheim", p1.GetEntity("Address")["City"]);
                Assert.AreEqual("Laurent", p1.GetEntitySet("Partners")[0]["Firstname"]);

                p1 = pe.LoadWithId("Person", p1.Id);

                Assert.IsNotNull(p1);
                Assert.AreEqual("Fabien", p1["Firstname"]);


            }
            catch (Exception e)
            {
                _exceptions.Add(e);
            }
        }

        [TestMethod]
        public virtual void BadMetadata()
        {
            //pe.InitializeRepository();
            EntitySet es;

            try
            {
                es = pe.Load("Wrong:Animal");
            }
            catch (Evaluant.Uss.Models.ModelElementNotFoundException)
            {
            }
            catch (Exception e)
            {
                Assert.Fail();
            }

            try
            {
                es = pe.Load("Person[Animal = 'Lion']");
            }
            catch (Evaluant.Uss.Models.ModelElementNotFoundException)
            {
            }
            catch (Evaluant.Uss.SqlMapper.MappingNotFoundException)
            {
            }
            catch (Exception e)
            {
                Assert.Fail(e.Message);
            }

            try
            {
                es = pe.Load("Person.MyHouse[ Roof = 'Paper' ]");
            }
            catch (Evaluant.Uss.Models.ModelElementNotFoundException)
            {
            }
            catch (Exception e)
            {
                Assert.Fail(e.Message);
            }

        }

        [TestMethod]
        public virtual void InheritanceLoadWithId()
        {
            // Loading with an Id using a base type should return a subtype
            //pe.InitializeRepository();

            Entity bill = new Entity("Employee");
            bill.Id = ("BILL");
            bill.AddValue("Firstname", "Bill Gates");
            bill.AddValue("Salary", 99999);

            Transaction t = new Transaction();
            t.Serialize(bill);
            t.Commit(pe);

            Assert.AreEqual(1, pe.Load("Person[ id('BILL') ]").Count);
            Assert.AreEqual(1, pe.Load("Employee[ id('BILL') ]").Count);

            Assert.IsNotNull(pe.LoadWithId("Person", "BILL"));
            Assert.IsNotNull(pe.LoadWithId("Employee", "BILL"));
        }

        [TestMethod]
        public virtual void Scalar()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "P1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "P2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "P3");

            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Commit(pe);

            object o = pe.LoadScalar("count(Person[Firstname = 'P1'].Partners)");
            Assert.AreEqual(typeof(int), o.GetType());

            Assert.AreEqual(1, pe.LoadScalar("count(Person[Firstname = 'P1'].Partners)"));
            Assert.AreEqual(1, pe.LoadScalar("count(Person[Firstname = 'P2'].Partners)"));
        }

        [TestMethod]
        public virtual void CachedQuery()
        {
            //pe.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            p1.AddValue("Partners", p3);
            p2.AddValue("Partners", p3);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Commit(pe);

            string id1 = p1.Id;
            string id2 = p2.Id;
            string id3 = p3.Id;

            p1 = null;
            p2 = null;
            p3 = null;

            GC.Collect();

            for (int i = 0; i < 100; i++)
            {
                Assert.AreEqual(1, pe.LoadScalar("count(Person[Firstname = 'p1'].Partners)"));
            }

            pe.Load("Person");

            DateTime begin = DateTime.Now;
            while (DateTime.Now - begin < new TimeSpan(0, 0, 20))
            {
                p1 = pe.LoadWithId("Person", id1);
                p2 = pe.LoadWithId("Person", id2);
                p3 = pe.LoadWithId("Person", id3);

                Assert.AreEqual("p1", p1["Firstname"]);
                Assert.AreEqual("p2", p2["Firstname"]);
                Assert.AreEqual("p3", p3["Firstname"]);

                pe.LoadReference(p1, new string[] { "Partners" });
                pe.LoadReference(p2, new string[] { "Partners" });
                pe.LoadReference(p3, new string[] { "Partners" });

                Assert.AreEqual(1, p1.GetEntitySet("Partners").Count);
                Assert.AreEqual(1, p2.GetEntitySet("Partners").Count);
                Assert.AreEqual(0, p3.GetEntitySet("Partners").Count);

                Assert.AreEqual("p3", p1.GetEntitySet("Partners")[0]["Firstname"]);
                Assert.AreEqual("p3", p2.GetEntitySet("Partners")[0]["Firstname"]);

                p1["Firstname"] = "xxx"; p1["Firstname"] = "p1";
                p2["Firstname"] = "xxx"; p2["Firstname"] = "p2";
                p3["Firstname"] = "xxx"; p3["Firstname"] = "p3";

                Assert.AreEqual("p1", p1["Firstname"]);
                Assert.AreEqual("p2", p2["Firstname"]);
                Assert.AreEqual("p3", p3["Firstname"]);

                t = new Transaction();
                t.Serialize(p1);
                t.Serialize(p2);
                t.Serialize(p3);
                t.Commit(pe);
            }
        }


        [TestMethod]
        public virtual void ShouldAllowInheritanceWithLoadWithId()
        {
            Entity p1 = new Entity("Person");
            Entity e1 = new Entity("Employee");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(e1);
            t.Commit(pe);

            p1 = pe.LoadWithId("Person", p1.Id);
            e1 = pe.LoadWithId("Person", e1.Id);

            Assert.IsNotNull(p1);
            Assert.IsNotNull(e1);

            Assert.AreEqual("Person", p1.Type);
            Assert.AreEqual("Employee", e1.Type);
        }

        [TestMethod]
        public virtual void HugeQuantity()
        {
            //pe.InitializeRepository();

            Transaction t = new Transaction();

            int length = 10000;
            for (int i = 0; i < length; i++)
            {
                Entity e = new Entity("Person");
                e.AddValue("Firstname", "firstname");
                e.AddValue("Age", i);

                t.Serialize(e);
            }

            t.Commit(pe);
        }

        [TestMethod]
        public virtual void ShouldHandleAttributesWithDescIn()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "John");
            p1.AddValue("ShortDescription", "A");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Smith");
            p2.AddValue("ShortDescription", "B");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Erik");
            p3.AddValue("ShortDescription", "B");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pe);

            EntitySet people = pe.Load("Person", "ShortDescription desc, Firstname desc", 1, 0);

            Assert.AreEqual(3, people.Count);
            Assert.AreEqual("Smith", people[0]["Firstname"]);
            Assert.AreEqual("Erik", people[1]["Firstname"]);
            Assert.AreEqual("John", people[2]["Firstname"]);


        }

        public virtual void ShouldLoadEntitiesWithAvgConstraint()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "John");
            p1.AddValue("Age", 18);

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Jane");
            p2.AddValue("Age", 20);

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "John");
            p3.AddValue("Age", 22);

            Entity p4 = new Entity("Person");
            p4.AddValue("Firstname", "John");
            p4.AddValue("Age", 24);

            Entity p5 = new Entity("Person");
            p5.AddValue("Firstname", "John");
            p5.AddValue("Age", 26);

            p1.AddValue("Partners", p2, State.New);
            p2.AddValue("Partners", p3, State.New);
            p1.AddValue("Partners", p3, State.New);
            p3.AddValue("Partners", p4, State.New);
            p3.AddValue("Partners", p5, State.New);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Serialize(p4);
            t.Serialize(p5);
            t.Commit(pe);

            Assert.IsTrue(pe.Load("Person[avg(Friends.Age)>=24]").Count > 0);
        }

        [TestMethod]
        public virtual void ShouldAcceptDeleteCommandsInCompoundUpdate()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "John");
            p1.AddValue("Age", 18);

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);

            p1.DeleteElement("Firstname");
            p1["Age"] = 12;

            t = new Transaction();
            t.Serialize(p1);
            t.Commit(pe);
        }

        [TestMethod]
        public virtual void ShouldReturnTheSameValueForCountAndList()
        {
            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "Fabien");
            p1.AddValue("Lastname", "Reinle");
            p1.Id = "p1";

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "Laurent");
            p2.AddValue("Lastname", "Kempe");
            p2.Id = "p2";

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "Sébastien");
            p3.AddValue("Lastname", "Ros");
            p3.Id = "p3";

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pe);

            Assert.AreEqual(pe.Load("Person").Count, pe.LoadScalar("count(Person)"));
            Assert.AreEqual(pe.Load("Person[Firstname ~ 'a' or Lastname ~'a']").Count, pe.LoadScalar("count(Person[Firstname ~ 'a' or Lastname ~'a'])"));

        }
    }
}
